﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FlexminAPI;
using System.Net.NetworkInformation;
using System.Net;
using SysTimer = System.Timers.Timer;

namespace NetStatistics
{
	public delegate void RefreshConnectionsDelegate(TcpConnectionInfo[] tcpConnections);
	public delegate void RefreshTcpUdpLinksDelegate(ActiveListener[] activeListeners);
	public delegate void RefreshAdaptersDelegate(NetworkAdapter[] adapters);

	public enum NetProtocol
	{
		TCP,
		UDP
	}

	public partial class NetForm : Form
	{
		private NetSlave slave;

		private bool die = false;

		private SysTimer updateTimer;

		public NetForm(ISlave slave)
		{
			InitializeComponent();

			this.slave = slave as NetSlave;

			FillInfo();

			updateTimer = new SysTimer(1000);
			updateTimer.Elapsed += new System.Timers.ElapsedEventHandler(updateTimer_Elapsed);		
			updateTimer.Enabled = true;

			this.slave.StartSpeedMonitoring();
		}

		private List<TcpConnectionInfo> tcpConnections = new List<TcpConnectionInfo>();
		private void FillConnections(TcpConnectionInfo[] tcpConnections)
		{
			if (!die)
			{
				if (this.InvokeRequired)
				{
					this.Invoke(new RefreshConnectionsDelegate(FillConnections), new object[] { tcpConnections });
					return;
				}

				bool found = false;
				List<TcpConnectionInfo> tcpConnectionsToAdd = new List<TcpConnectionInfo>();
				List<TcpConnectionInfo> tcpConnectionsToDelete = new List<TcpConnectionInfo>();

				for (int i = 0; i < tcpConnections.Length; i++)
				{
					found = false;

					for (int j = 0; j < this.tcpConnections.Count; j++)
					{
						if (this.tcpConnections[j].Equals(tcpConnections[i]))
						{
							if (this.tcpConnections[j].State != tcpConnections[i].State)
							{
								this.tcpConnections[j].State = tcpConnections[i].State;
								ListViewItem item = connectionsList.Items[j];
								item.SubItems[2].Text = this.tcpConnections[j].State;

								#region Coloring list
								switch (this.tcpConnections[j].State)
								{
									case "Unknown":
										item.ForeColor = Color.White;
										item.BackColor = Color.Gray;
										break;
									case "Closed":
										item.ForeColor = Color.DarkGray;
										break;
									case "CloseWait":
										item.BackColor = Color.LightGray;
										break;
									case "Closing":
										item.ForeColor = Color.Gray;
										break;
									case "Established":
										item.ForeColor = Color.DarkGreen;
										break;
									case "FinWait1":
										item.ForeColor = Color.OrangeRed;
										break;
									case "FinWait2":
										item.ForeColor = Color.Orange;
										break;
									case "LastAck":
										item.ForeColor = Color.Orchid;
										break;
									case "Listen":
										item.ForeColor = Color.Blue;
										break;
									case "SynReceived":
										item.BackColor = Color.Orange;
										break;
									case "SynSent":
										item.BackColor = Color.LightGreen;
										break;
									case "TimeWait":
										item.ForeColor = Color.MediumBlue;
										break;
								}
								#endregion

								connectionsList.Items[j] = item;
							}

							found = true;
							break;
						}
					}

					if (found)
						continue;

					tcpConnectionsToAdd.Add(tcpConnections[i]);
				}

				for (int i = 0; i < this.tcpConnections.Count; i++)
				{
					found = false;

					for (int j = 0; j < tcpConnections.Length; j++)
					{
						if (tcpConnections[j].Equals(this.tcpConnections[i]))
						{
							found = true;
							break;
						}
					}

					if (found)
						continue;

					tcpConnectionsToDelete.Add(this.tcpConnections[i]);
				}

				foreach (TcpConnectionInfo tcpConnection in tcpConnectionsToAdd)
				{
					this.tcpConnections.Add(tcpConnection);

					ListViewItem item = new ListViewItem(tcpConnection.LocalAddress + ":" + tcpConnection.LocalPort.ToString());
					item.SubItems.Add(tcpConnection.RemoteAddress + ":" + tcpConnection.RemotePort.ToString());
					item.SubItems.Add(tcpConnection.State);

					#region Coloring list
					switch (tcpConnection.State)
					{
						case "Unknown":
							item.ForeColor = Color.White;
							item.BackColor = Color.Gray;
							break;
						case "Closed":
							item.ForeColor = Color.DarkGray;
							break;
						case "CloseWait":
							item.BackColor = Color.LightGray;
							break;
						case "Closing":
							item.ForeColor = Color.Gray;
							break;
						case "Established":
							item.ForeColor = Color.DarkGreen;
							break;
						case "FinWait1":
							item.ForeColor = Color.OrangeRed;
							break;
						case "FinWait2":
							item.ForeColor = Color.Orange;
							break;
						case "LastAck":
							item.ForeColor = Color.Orchid;
							break;
						case "Listen":
							item.ForeColor = Color.Blue;
							break;
						case "SynReceived":
							item.BackColor = Color.Orange;
							break;
						case "SynSent":
							item.BackColor = Color.LightGreen;
							break;
						case "TimeWait":
							item.ForeColor = Color.MediumBlue;
							break;
					}
					#endregion

					connectionsList.Items.Add(item);
				}

				foreach (TcpConnectionInfo tcpConnection in tcpConnectionsToDelete)
				{
					this.tcpConnections.Remove(tcpConnection);

					for (int i = 0; i < connectionsList.Items.Count; i++)
					{
						if (connectionsList.Items[i].Text == tcpConnection.LocalAddress + ":" + tcpConnection.LocalPort.ToString()
							&& connectionsList.Items[i].SubItems[1].Text == tcpConnection.RemoteAddress + ":" + tcpConnection.RemotePort.ToString())
						{
							connectionsList.Items[i].Remove();
							break;
						}
					}
				}
			}
		}

		private List<NetworkAdapter> adapters = new List<NetworkAdapter>();
		private void FillAdapters(NetworkAdapter[] adapters)
		{
			if (!die)
			{
				if (this.InvokeRequired)
				{
					this.Invoke(new RefreshAdaptersDelegate(FillAdapters), new object[] { adapters });
					return;
				}

				bool found = false;
				List<NetworkAdapter> adaptersToAdd = new List<NetworkAdapter>();
				List<NetworkAdapter> adaptersToDelete = new List<NetworkAdapter>();

				for (int i = 0; i < adapters.Length; i++)
				{
					found = false;

					for (int j = 0; j < this.adapters.Count; j++)
					{
						if (this.adapters[j].Name == adapters[i].Name)
						{
							if (!this.adapters[j].Equals(adapters[i]))
							{
								this.adapters[j] = adapters[i];

								adaptersList.Items[j].SubItems[1].Text = String.Format("{0:0.0}", this.adapters[j].DownloadSpeed) + " KB/s";
								adaptersList.Items[j].SubItems[2].Text = String.Format("{0:0.0}", this.adapters[j].UploadSpeed) + "KB/s";
							}

							found = true;
							break;
						}
					}

					if (found)
						continue;

					adaptersToAdd.Add(adapters[i]);
				}

				for (int i = 0; i < this.adapters.Count; i++)
				{
					found = false;

					for (int j = 0; j < adapters.Length; j++)
					{
						if (adapters[j].Name == this.adapters[i].Name)
						{
							found = true;
							break;
						}
					}

					if (found)
						continue;

					adaptersToDelete.Add(this.adapters[i]);
				}

				foreach (NetworkAdapter adapter in adaptersToAdd)
				{
					this.adapters.Add(adapter);

					ListViewItem item = new ListViewItem(adapter.Name);
					item.SubItems.Add(String.Format("{0:0.0}", adapter.DownloadSpeed) + " KB/s");
					item.SubItems.Add(String.Format("{0:0.0}", adapter.UploadSpeed) + " KB/s");

					adaptersList.Items.Add(item);
				}

				foreach (NetworkAdapter adapter in adaptersToDelete)
				{
					this.adapters.Remove(adapter);
					for (int i = 0; i < adaptersList.Items.Count; i++)
					{
						if (adaptersList.Items[i].Text == adapter.Name)
						{
							adaptersList.Items[i].Remove();
							break;
						}
					}
				}
			}
		}

		private List<ActiveListener> activeListeners = new List<ActiveListener>();
		private void FillTcpUdpConnections(ActiveListener[] activeListeners)
		{
			if (!die)
			{
				if (this.InvokeRequired)
				{
					this.Invoke(new RefreshTcpUdpLinksDelegate(FillTcpUdpConnections), new object[] { activeListeners });
					return;
				}

				bool found = false;

				List<ActiveListener> activeListenersToAdd = new List<ActiveListener>();
				List<ActiveListener> activeListenersToDelete = new List<ActiveListener>();

				for (int i = 0; i < activeListeners.Length; i++)
				{
					found = false;

					for (int j = 0; j < this.activeListeners.Count; j++)
					{
						if (this.activeListeners[j].Equals(activeListeners[i]))
						{
							found = true;
							break;
						}
					}

					if (found)
						continue;

					activeListenersToAdd.Add(activeListeners[i]);
				}

				for (int i = 0; i < this.activeListeners.Count; i++)
				{
					found = false;

					for (int j = 0; j < activeListeners.Length; j++)
					{
						if (this.activeListeners[i].Equals(activeListeners[j]))
						{
							found = true;
							break;
						}
					}

					if (found)
						continue;

					activeListenersToDelete.Add(this.activeListeners[i]);
				}

				foreach (ActiveListener activeListener in activeListenersToAdd)
				{
					this.activeListeners.Add(activeListener);

					ListViewItem item = new ListViewItem(activeListener.Address.ToString());
					item.SubItems.Add(activeListener.Port.ToString());
					item.SubItems.Add(activeListener.Protocol.ToString());

					tcpUdpLinksList.Items.Add(item);
				}

				foreach (ActiveListener activeListener in activeListenersToDelete)
				{
					this.activeListeners.Remove(activeListener);

					for (int i = 0; i < tcpUdpLinksList.Items.Count; i++)
					{
						if (tcpUdpLinksList.Items[i].Text == activeListener.Address.ToString()
							&& tcpUdpLinksList.Items[i].SubItems[1].Text == activeListener.Port.ToString()
							&& tcpUdpLinksList.Items[i].SubItems[2].Text == activeListener.Protocol.ToString())
						{
							tcpUdpLinksList.Items[i].Remove();
							break;
						}
					}
				}
			}
		}

		private void FillInfo()
		{
			slave.Refresh();
			
			this.compNameBox.Text = slave.HostName;
			this.domainNameBox.Text = slave.DomainName;
			this.nodeTypeBox.Text = slave.NodeType;
			this.dhcpScopeBox.Text = slave.DhcpScopeName;

			TcpConnectionInfo[] tcpConnections = slave.GetActiveTcpConnections();
			FillConnections(tcpConnections);

			ActiveListener[] activeListeners = slave.GetActiveListeners();
			FillTcpUdpConnections(activeListeners);

			NetworkAdapter[] adapters = slave.GetAdapters();
			FillAdapters(adapters);
		}

		private void updateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			if (!die)
				FillInfo();
			else
			{
				updateTimer.Stop();
				updateTimer.Close();
			}
		}

		private void enableToolStripMenuItem_Click(object sender, EventArgs e)
		{
			// Not implemented yet
		}

		private void disableToolStripMenuItem_Click(object sender, EventArgs e)
		{
			// Not implemented yet
		}

		private void NetForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			die = true;			
		}
	}
}
